home *** CD-ROM | disk | FTP | other *** search
- /* SPIM S20 MIPS simulator.
- Code to create, maintain and access memory.
- Copyright (C) 1990 by James Larus (larus@cs.wisc.edu).
-
- SPIM is free software; you can redistribute it and/or modify it
- under the terms of the GNU General Public License as published by the
- Free Software Foundation; either version 1, or (at your option) any
- later version.
-
- SPIM is distributed in the hope that it will be useful, but WITHOUT
- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- for more details.
-
- You should have received a copy of the GNU General Public License
- along with GNU CC; see the file COPYING. If not, write to James R.
- Larus, Computer Sciences Department, University of Wisconsin--Madison,
- 1210 West Dayton Street, Madison, WI 53706, USA or to the Free
- Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
-
-
- /* $Header: /var/home/cs354/.spim/RCS/mem.c,v 1.4 1992/10/12 11:34:05 cs354 Exp $
- */
-
-
- #include <stdio.h>
- #include "spim.h"
- #include "inst.h"
- #define MEM_MAIN
- #include "mem.h"
- #define REG_MAIN
- #include "reg.h"
-
-
- /* Local functions: */
-
- static void free_instructions(instruction **inst ,int n);
-
-
- /* Local variables: */
-
- static long data_size_limit, stack_size_limit, k_data_size_limit;
-
-
-
- /* Memory is allocated in five chunks:
- text, data, stack, kernel text, and kernel data.
-
- The arrays are independent and have different semantics.
-
- text is allocated from 0x400000 up and only contains INSTRUCTIONs.
- It does not expand.
-
- data is allocated from 0x10000000 up. It can be extended by the
- SBRK system call. Programs can only read and write this segment.
-
- stack grows from 0x7fffefff down. It is automatically extended.
- Programs can only read and write this segment.
-
- k_text is like text, except its is allocated from 0x80000000 up.
-
- k_data is like data, but is allocated from 0x90000000 up.
-
- Both kernel text and kernel data can only be accessed in kernel mode.
- */
-
- #ifdef MACINTOSH
-
- /* Here are the memory and register access functions that are macros in the non-Mac
- versions of SPIM.
- */
-
- mem_addr MEM_ADDRESS(mem_addr addr)
- {
- if ( (addr >= TEXT_BOT) && (addr < text_top) )
- return addr - TEXT_BOT + (mem_addr) text_seg;
- if ( (addr >= DATA_BOT) && (addr < data_top) )
- return addr - DATA_BOT + (mem_addr) data_seg;
- if ( (addr >= stack_bot) && (addr < STACK_TOP) )
- return addr - stack_bot + (mem_addr) stack_seg;
- if ( (addr >= K_TEXT_BOT) && (addr < k_text_top) )
- return addr - K_TEXT_BOT + (mem_addr) k_text_seg;
- if ( (addr >= K_DATA_BOT) && (addr < k_data_top) )
- return addr - K_DATA_BOT + (mem_addr) k_data_seg;
- run_error("Memory address out of bounds\n");
- } /* MEM_ADDRESS */
-
- #endif
-
-
- void make_memory (long text_size, long data_size, long data_limit,
- long stack_size, long stack_limit, long k_text_size, long k_data_size,
- long k_data_limit)
- {
- if (data_size <= 65536)
- fatal_error ("Data segment must be larger than 64K\n");
- if (text_seg == NULL)
- text_seg = (instruction **)
- malloc (sizeof (instruction *) * text_size / BYTES_PER_WORD);
- else
- free_instructions (text_seg, (text_top - TEXT_BOT) / BYTES_PER_WORD);
- if (text_seg == NULL)
- fatal_error ("malloc failed in make_memory\n");
- bzero (text_seg, sizeof (instruction *) * text_size / BYTES_PER_WORD);
- text_top = TEXT_BOT + text_size;
-
- if (data_seg == NULL)
- data_seg =
- (mem_word *) malloc (sizeof (mem_word) * data_size / BYTES_PER_WORD);
- if (data_seg == NULL)
- fatal_error ("malloc failed in make_memory\n");
- bzero (data_seg, sizeof (instruction *) * data_size / BYTES_PER_WORD);
- data_seg_b = (BYTE_TYPE *) data_seg;
- data_seg_h = (short *) data_seg;
- data_top = DATA_BOT + data_size;
- data_size_limit = data_limit;
-
- if (stack_seg == NULL)
- stack_seg =
- (mem_word *) malloc (sizeof (mem_word) * stack_size / BYTES_PER_WORD);
- if (stack_seg == NULL)
- fatal_error ("malloc failed in make_memory\n");
- bzero (stack_seg, sizeof (instruction *) * stack_size / BYTES_PER_WORD);
- stack_seg_b = (BYTE_TYPE *) stack_seg;
- stack_seg_h = (short *) stack_seg;
- stack_bot = STACK_TOP - stack_size;
- stack_size_limit = stack_limit;
-
- if (k_text_seg == NULL)
- k_text_seg = (instruction **)
- malloc (sizeof (instruction *) * k_text_size / BYTES_PER_WORD);
- else
- free_instructions (k_text_seg, (k_text_top - K_TEXT_BOT) / BYTES_PER_WORD);
- if (k_text_seg == NULL)
- fatal_error ("malloc failed in make_memory\n");
- bzero (k_text_seg, sizeof (instruction *) * k_text_size / BYTES_PER_WORD);
- k_text_top = K_TEXT_BOT + k_text_size;
-
- if (k_data_seg == NULL)
- k_data_seg =
- (mem_word *) malloc (sizeof (mem_word) * k_data_size / BYTES_PER_WORD);
- if (k_data_seg == NULL)
- fatal_error ("malloc failed in make_memory\n");
- bzero (k_data_seg, sizeof (instruction *) * k_data_size / BYTES_PER_WORD);
- k_data_seg_b = (BYTE_TYPE *) k_data_seg;
- k_data_seg_h = (short *) k_data_seg;
- k_data_top = K_DATA_BOT + k_data_size;
- k_data_size_limit = k_data_limit;
-
- text_modified = 0;
- data_modified = 0;
- }
-
-
- /* Free the storage used by the old instructions in memory. */
-
- static void free_instructions (register instruction **inst, int n)
- {
- for ( ; n > 0; n --, inst ++)
- if (*inst)
- {
- if (EXPR (*inst))
- free (EXPR (*inst));
- free (*inst);
- }
- }
-
-
- /* Expand the data segment by adding N bytes. */
-
- void expand_data (long addl_bytes)
- {
- long old_size = data_top - DATA_BOT;
- long new_size = old_size + addl_bytes;
- register mem_word *p;
-
- #ifdef MACINTOSH
- error("You're not allowed to expand_data() on the Macintosh.\n");
- #endif
-
- if (addl_bytes < 0 || (source_file && new_size > data_size_limit))
- {
- sprintf(mess_buff,
- "Can't expand data segment by %d bytes to %d bytes\n",
- addl_bytes, new_size);
- error (mess_buff);
- sprintf(mess_buff, "Use -ldata # with # > %d\n", new_size);
- run_error (mess_buff);
- }
- data_seg = (mem_word *) realloc (data_seg, new_size);
- if (data_seg == NULL)
- fatal_error ("realloc failed in expand_data\n");
- data_seg_b = (BYTE_TYPE *) data_seg;
- data_seg_h = (short *) data_seg;
- for (p = data_seg + old_size / BYTES_PER_WORD;
- p < data_seg + new_size / BYTES_PER_WORD; )
- *p ++ = 0;
- data_top += addl_bytes;
- }
-
-
- /* Expand the stack segment by adding N bytes. Can't use REALLOC
- since it copies from bottom of memory blocks and stack grows down from
- top of its block. */
-
- void expand_stack (long addl_bytes)
- {
- long old_size = STACK_TOP - stack_bot;
- long new_size = old_size + addl_bytes;
- mem_word *new_seg;
- register mem_word *po, *pn;
-
- #ifdef MACINTOSH
- error("You're not allowed to expand_stack() on the Macintosh.\n");
- #endif
-
- if (addl_bytes < 0 || (source_file && new_size > stack_size_limit))
- {
- sprintf(mess_buff,
- "Can't expand stack segment by %d bytes to %d bytes\n",
- addl_bytes, new_size);
- error (mess_buff);
- sprintf(mess_buff, "Use -lstack # with # > %d\n", new_size);
- run_error (mess_buff);
- }
-
- new_seg = (mem_word *) malloc (new_size);
- if (new_seg == NULL)
- fatal_error ("malloc failed in expand_stack\n");
- po = stack_seg + old_size / BYTES_PER_WORD;
- pn = new_seg + new_size / BYTES_PER_WORD;
-
- for ( ; po >= stack_seg ; ) *pn -- = *po --;
- for ( ; pn >= new_seg ; ) *pn -- = 0;
-
- stack_seg = new_seg;
- stack_seg_b = (BYTE_TYPE *) stack_seg;
- stack_seg_h = (short *) stack_seg;
- stack_bot -= addl_bytes;
- }
-
-
- /* Expand the kernel data segment by adding N bytes. */
-
- void expand_k_data (long addl_bytes)
- {
- long old_size = k_data_top - K_DATA_BOT;
- long new_size = old_size + addl_bytes;
- register mem_word *p;
-
- #ifdef MACINTOSH
- error("You're not allowed to expand_k_data() on the Macintosh.\n");
- #endif
-
- if (addl_bytes < 0 || (source_file && new_size > k_data_size_limit))
- {
- sprintf(mess_buff,
- "Can't expand kernel data segment by %d bytes to %d bytes\n",
- addl_bytes, new_size);
- error (mess_buff);
- sprintf(mess_buff, "Use -lkdata # with # > %d\n", new_size);
- run_error (mess_buff);
- }
- k_data_seg = (mem_word *) realloc (k_data_seg, new_size);
- if (k_data_seg == NULL)
- fatal_error ("realloc failed in expand_k_data\n");
- k_data_seg_b = (BYTE_TYPE *) k_data_seg;
- k_data_seg_h = (short *) k_data_seg;
- for (p = k_data_seg + old_size / BYTES_PER_WORD;
- p < k_data_seg + new_size / BYTES_PER_WORD; )
- *p ++ = 0;
- k_data_top += addl_bytes;
- }
-
-
- instruction * funny_text_read (mem_addr addr)
- {
- mem_word bits;
-
- READ_MEM_WORD (bits, addr);
- return (inst_decode (bits));
- }
-
-
- void funny_text_write (mem_addr addr, instruction *inst)
- {
- mem_word bits = inst_encode (inst);
-
- SET_MEM_WORD (addr, bits);
- }
-
-
- mem_word bad_mem_read (mem_addr addr, int mask, mem_word *dest)
- {
- if (addr & mask)
- RAISE_EXCEPTION (ADDRL_EXCPT, BadVAddr = addr)
- else if (addr >= TEXT_BOT && addr < text_top)
- {
- if (mask != 0x3)
- run_error ("SPIM restriction: Can only read text segment by words\n");
- else
- return (inst_encode (text_seg [(addr - TEXT_BOT) >> 2]));
- }
- else if (addr > data_top
- && addr < stack_bot
- /* If more than 16 MB below stack, probably is bad data ref */
- && addr > stack_bot - 16*1000*K)
- {
- /* Grow stack segment */
- expand_stack (stack_bot - addr + 4);
- *dest = 0; /* Newly allocated memory */
- }
- else
- /* Address out of range */
- RAISE_EXCEPTION (DBUS_EXCPT, BadVAddr = addr)
- return (0);
- }
-
-
- void bad_mem_write (mem_addr addr, mem_word value, int mask)
- {
- if (addr & mask)
- /* Unaligned address fault */
- RAISE_EXCEPTION (ADDRS_EXCPT, BadVAddr = addr)
- else if (addr >= TEXT_BOT && addr < text_top)
- {
- if (mask != 0x3)
- run_error ("SPIM restriction: Can only write text segment by words\n");
- else
- text_seg [(addr - TEXT_BOT) >> 2] = inst_decode (value);
- }
- else if (addr > data_top
- && addr < stack_bot
- /* If more than 16 MB below stack, probably is bad data ref */
- && addr > stack_bot - 16*1000*K)
- {
- /* Grow stack segment */
- expand_stack (stack_bot - addr + 4);
- if (addr >= stack_bot)
- {
- if (mask == 0)
- stack_seg_b [addr - stack_bot] = value;
- else if (mask == 1)
- stack_seg_h [addr - stack_bot] = value;
- else
- stack_seg [addr - stack_bot] = value;
- }
- else
- RAISE_EXCEPTION (DBUS_EXCPT, BadVAddr = addr)
- }
- else
- /* Address out of range */
- RAISE_EXCEPTION (DBUS_EXCPT, BadVAddr = addr)
- }
-
-
- void print_mem (mem_addr addr)
- {
- long value;
-
- if (TEXT_BOT <= addr && addr < text_top)
- print_inst (addr);
- else if (DATA_BOT <= addr && addr < data_top)
- {
- READ_MEM_WORD (value, addr);
- sprintf(mess_buff, "Data seg @ 0x%08x (%d) = 0x%08x (%d)\n",
- addr, addr, value, value);
- write_output (message_out, mess_buff);
- }
- else if (stack_bot <= addr && addr < STACK_TOP)
- {
- READ_MEM_WORD (value, addr);
- sprintf(mess_buff, "Stack seg @ 0x%08x (%d) = 0x%08x (%d)\n",
- addr, addr, value, value);
- write_output (message_out, mess_buff);
- }
- else if (K_TEXT_BOT <= addr && addr < k_text_top)
- print_inst (addr);
- else if (K_DATA_BOT <= addr && addr < k_data_top)
- {
- READ_MEM_WORD (value, addr);
- sprintf(mess_buff, "Kernel Data seg @ 0x%08x (%d) = 0x%08x (%d)\n",
- addr, addr, value, value);
- write_output (message_out, mess_buff);
- }
- else {
- sprintf(mess_buff,
- "Address 0x%08x (%d) to print_mem is out of bounds\n", addr, addr);
- error (mess_buff);
- }
- }
-